home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / CUGUK / GAMES / C014.ZIP / LARN_SRC.ZIP / MSDOS.C < prev    next >
C/C++ Source or Header  |  1993-11-17  |  12KB  |  482 lines

  1. #ifdef MSDOS
  2. # include <stdio.h>
  3. # include <process.h>
  4. # include <dos.h>
  5. # include <fcntl.h>
  6. # include <sys/types.h>
  7. # include <sys/stat.h>
  8. # include "header.h"
  9. # include "larndefs.h"
  10.  
  11. # define DEVICE     0x80
  12. # define RAW        0x20
  13. # define IOCTL      0x44
  14. # define STDIN      0
  15. # define STDOUT     1
  16. # define GETBITS    0
  17. # define SETBITS    1
  18. # define PATHSEP    ';'
  19.  
  20. /* Normal characters are output when the shift key is not pushed.
  21.  * Shift characters are output when either shift key is pushed.
  22.  */
  23. #  define KEYPADHI  83
  24. #  define KEYPADLOW 71
  25. #  define iskeypad(x)   (KEYPADLOW <= (x) && (x) <= KEYPADHI)
  26. static struct {
  27.     char normal, shift;
  28.     } pad[KEYPADHI - KEYPADLOW + 1] = {
  29.             {'y', 'Y'},     /* 7 */
  30.             {'k', 'K'},     /* 8 */
  31.             {'u', 'U'},     /* 9 */
  32.             {' ', ' '},     /* - */
  33.             {'h', 'H'},     /* 4 */
  34.             {' ', ' '},     /* 5 */
  35.             {'l', 'L'},     /* 6 */
  36.             {' ', ' '},     /* + */
  37.             {'b', 'B'},     /* 1 */
  38.             {'j', 'J'},     /* 2 */
  39.             {'n', 'N'},     /* 3 */
  40.             {'i', 'i'},     /* Ins */
  41.             {'.', '.'}      /* Del */
  42. };
  43.  
  44. /* BIOSgetch gets keys directly with a BIOS call.
  45.  */
  46. #ifdef    OS2LARN
  47. # define SHIFT       (RIGHTSHIFT | LEFTSHIFT)
  48. #else
  49. # define SHIFT       (0x1 | 0x2)
  50. #endif
  51. #  define KEYBRD_BIOS   0x16
  52.  
  53. static char
  54. BIOSgetch() {
  55.     unsigned char scan, shift, ch;
  56.     union REGS regs;
  57.  
  58. #ifdef    OS2LARN
  59.     KBDKEYINFO  kbd;
  60.  
  61.     KbdCharIn(&kbd,IO_WAIT,(HKBD) 0);
  62.     ch    = kbd.chChar;
  63.     scan  = kbd.chScan;
  64.     shift = kbd.fsState;
  65. #else
  66.     /* Get scan code.
  67.     */
  68.     regs.h.ah = 0;
  69.     int86(KEYBRD_BIOS, ®s, ®s);
  70.     ch = regs.h.al;
  71.     scan = regs.h.ah;
  72.  
  73.     /* Get shift status.
  74.      */
  75.     regs.h.ah = 2;
  76.     int86(KEYBRD_BIOS, ®s, ®s);
  77.     shift = regs.h.al;
  78. #endif
  79.  
  80.     /* If scan code is for the keypad, translate it.
  81.      */
  82.     if (iskeypad(scan)) {
  83.         if (shift & SHIFT)
  84.             ch = pad[scan - KEYPADLOW].shift;
  85.         else
  86.             ch = pad[scan - KEYPADLOW].normal;
  87.     }
  88.     return ch;
  89. }
  90.  
  91. kgetch()
  92. {
  93.     /* BIOSgetch can use the numeric key pad on IBM compatibles. */
  94.     if (keypad)
  95.         return BIOSgetch();
  96.     else
  97.         return getch();
  98. }
  99.  
  100. doshell()
  101. {
  102.     char *comspec = getenv("COMSPEC");
  103.  
  104.     clear();
  105.     lflush();
  106.     if (comspec == NULL
  107.     || (spawnl(P_WAIT, comspec, comspec, NULL) < 0)) {
  108.         write(2, "A> ", 3);
  109.         while (getche() != '\r')
  110.             ;
  111.     }
  112. }
  113.  
  114. static  unsigned    old_stdin, old_stdout, ioctl();
  115.  
  116. static unsigned
  117. ioctl(handle, mode, setvalue)
  118. unsigned setvalue;
  119. {
  120. #ifndef OS2LARN
  121.     union REGS regs;
  122.  
  123.     regs.h.ah = IOCTL;
  124.     regs.h.al = mode;
  125.     regs.x.bx = handle;
  126.     regs.h.dl = setvalue;
  127.     regs.h.dh = 0;          /* Zero out dh */
  128.     intdos(®s, ®s);
  129.     return (regs.x.dx);
  130. #endif
  131. }
  132.  
  133. int rawio;
  134. void
  135. setraw()
  136. {
  137.     if (!rawio)
  138.         return;
  139.     old_stdin = ioctl(STDIN, GETBITS, 0);
  140.     old_stdout = ioctl(STDOUT, GETBITS, 0);
  141.     if (old_stdin & DEVICE)
  142.         (void) ioctl(STDIN, SETBITS, old_stdin | RAW);
  143.     if (old_stdout & DEVICE)
  144.         (void) ioctl(STDOUT, SETBITS, old_stdout | RAW);
  145. }
  146.  
  147. void
  148. unsetraw()
  149. {
  150.     if (!rawio)
  151.         return;
  152.     if (old_stdin)
  153.         (void) ioctl(STDIN, SETBITS, old_stdin);
  154.     if (old_stdout)
  155.         (void) ioctl(STDOUT, SETBITS, old_stdout);
  156. }
  157.  
  158.  
  159. /* Add a backslash to any name not ending in /, \ or :   There must
  160.  * be room for the \
  161.  */
  162. void
  163. append_slash(name)
  164. char *name;
  165. {
  166.     char *ptr;
  167.  
  168.     if (!*name)
  169.         return;
  170.     ptr = name + (strlen(name) - 1);
  171.     if (*ptr != '\\' && *ptr != '/' && *ptr != ':') {
  172.         *++ptr = '\\';
  173.         *++ptr = '\0';
  174.     }
  175. }
  176.  
  177. /* Lopen a file somewhere along the PATH
  178.  */
  179. plopen(name)
  180. char    *name;
  181. {
  182.     char    buf[PATHLEN], *bp, *pp, lastch, *strchr();
  183.     int fd;
  184.  
  185.     /* Try the default directory first.  Then look along PATH unless
  186.      * the name has path components.
  187.      */
  188.     if ((fd = lopen(name)) >= 0)
  189.         return fd;
  190.     else if (strpbrk(name, "\\/:") == NULL) {
  191.         pp = getenv("PATH");
  192.         while (pp && *pp) {
  193.             bp = buf;
  194.             while (*pp && *pp != PATHSEP)
  195.                 lastch = *bp++ = *pp++;
  196.             if (strchr("\\/:", lastch) == NULL)
  197.                 *bp++ = '\\';
  198.             strcpy(bp, name);
  199.             if ((fd = lopen(buf)) >= 0)
  200.                 return fd;
  201.             if (*pp)
  202.                 pp++;
  203.         }
  204.     }
  205.     return -1;
  206. }
  207.  
  208.  
  209. /* Follow the PATH, trying to fopen the file.  Takes one additional
  210.  * argument which can be NULL.  Otherwise this argument gets filled
  211.  * in the full path to the file.  Returns as does fopen().
  212.  */
  213. FILE *
  214. fopenp(name, mode, pathname)
  215. char *name, *mode, *pathname;
  216. {
  217.     char buffer[BUFSIZ], *buf, *bufp, *pathp, *getenv(), lastch;
  218.     FILE *fp;
  219.  
  220.     /* If pathname is given, use it instead of buf so the calling
  221.      * process knows the path we found name under
  222.      */
  223.     if (pathname)
  224.         buf = pathname;
  225.     else
  226.         buf = buffer;
  227.  
  228.     /* Try the default directory first.  If the file can't be opened,
  229.      * start looking along the path.
  230.      */
  231.     strcpy(buf, name);
  232.     if (fp = fopen(buf, mode))
  233.         return fp;
  234.     else if (strpbrk(name, "\\/:") == NULL) {
  235.         pathp = getenv("PATH");
  236.         while (pathp && *pathp) {
  237.             bufp = buf;
  238.             while (*pathp && *pathp != PATHSEP)
  239.                 lastch = *bufp++ = *pathp++;
  240.             if (lastch != '\\' && lastch != '/')
  241.                 *bufp++ = '\\';
  242.             strcpy(bufp, name);
  243.             if (fp = fopen(buf, mode))
  244.                 return fp;
  245.             if (*pathp)
  246.                 pathp++;
  247.         }
  248.     }
  249.     return NULL;
  250. }
  251.  
  252. /* Diagnositic information about the disposition of levels between ram
  253.  * and disk.
  254.  */
  255. levelinfo()
  256. {
  257.     DISKBLOCK   *dp;
  258.     RAMBLOCK    *rp;
  259.  
  260.     cursors();
  261.     lflush();
  262.     fprintf(stderr, "\nRAM:\n");
  263.     for (rp = ramblks; rp; rp = rp->next)
  264.         fprintf(stderr, "%4d  gt:%6ld\n", rp->level, rp->gtime);
  265.     fprintf(stderr, "\nDISK:\n");
  266.     for (dp = diskblks; dp; dp = dp->next)
  267.         fprintf(stderr, "%4d  gt:%6ld  fpos:%ld\n",
  268.         dp->level, dp->gtime, dp->fpos);
  269.     nomove=1;
  270.     return (yrepcount = 0);
  271. }
  272.  
  273. int swapfd = 0; /* file descriptor for the swap file */
  274. int ramlevels = MAXLEVEL + MAXVLEVEL;   /* the maximum */
  275.  
  276.  
  277. /* Allocate as many levels as possible, then check that the swap file
  278.  * will have enough storage for the overflow.  You must be able to allocate
  279.  * at least one level or there will be nowhere to swap to/from.  If a swap
  280.  * file is opened it remains open for the whole game.
  281.  */
  282. allocate_memory()
  283. {
  284.     register int    i;
  285.     DISKBLOCK   *dp, *dp2;
  286.     RAMBLOCK    *rp;
  287.  
  288.     /* First allocate the maximum number of disk blocks, some of which
  289.      * may not be used, but must do the allocation now since we don't
  290.      * yet know how many levels will be allocatable.
  291.      */
  292.     for (i = 0; i < MAXLEVEL + MAXVLEVEL; i++) {
  293.         if ((dp = (DISKBLOCK *) malloc(sizeof(DISKBLOCK))) == NULL)
  294.             died(-285);
  295.         dp->next = diskblks;
  296.         diskblks = dp;
  297.     }
  298.     dp = diskblks;      /* Move this along in the next loop */
  299.  
  300.     /* Now allocate ram storage, up to ramlevels in count.
  301.      */
  302.     for (i = 0; i < MAXLEVEL + MAXVLEVEL; i++) {
  303.         if (i < ramlevels)
  304.             rp = (RAMBLOCK *) malloc(sizeof(RAMBLOCK));
  305.         else
  306.             rp = NULL;
  307.         if (rp == NULL) {
  308.             if (i == 0)
  309.                 died(-285); /* have to have at least one */
  310.  
  311.             /* Open the swap file if not yet done so
  312.              */
  313.             if (swapfd == 0) {
  314.                 swapfd = open(swapfile,
  315.                     O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
  316.                     S_IWRITE | S_IREAD);
  317.                 if (swapfd < 0)
  318.                     error("Can't open swapfile `%s'\n",
  319.                     swapfile);
  320.  
  321.                 /* First block is FREE and will be used to
  322.                  * swap out the first level.  When another
  323.                  * level gets swapped in, its block will be
  324.                  * FREE.
  325.                  */
  326.                 if (dp == NULL)
  327.                     error("NULL1 disk pointer?\n");
  328.                 dp->level = FREEBLOCK;
  329.                 dp->fpos = 0;
  330.                 dp->gtime = 0;
  331.                 lseek(swapfd, (long) sizeof rp->cell, 0);
  332.             }
  333.  
  334.             /* And try to seek the size of this level
  335.              */
  336.             dp = dp->next;
  337.             if (dp == NULL)
  338.                 error("NULL2 disk pointer?\n");
  339.             dp->level = FREEBLOCK;
  340.             dp->gtime = 0;
  341.             dp->fpos = tell(swapfd);
  342.             if (lseek(swapfd, (long) sizeof rp->cell, 1) < 0L)
  343.                 error("Not enough disk space for swapfile `%s'\n",
  344.                 swapfile);
  345.         } else {
  346.             rp->next = ramblks;
  347.             ramblks = rp;
  348.             rp->level = FREEBLOCK;
  349.             rp->gtime = 0;
  350.         }
  351.     }
  352.  
  353.     /* dp now points to the last diskblock used.  Truncate the diskblock
  354.      * list here and free up the other blocks (for what it's worth ...)
  355.      */
  356.     dp2 = dp->next;
  357.     dp->next = NULL;
  358.     dp = dp2;
  359.     while (dp) {
  360.         dp2 = dp->next;
  361.         free((char *) dp);
  362.         dp = dp2;
  363.     }
  364. }
  365.  
  366.  
  367. /* VARARGS1 */
  368. warn(format, a1, a2, a3)
  369. char *format;
  370. long a1, a2, a3;
  371. {
  372.     fprintf(stderr, format, a1, a2, a3);
  373. }
  374.  
  375. /* VARARGS1 */
  376. error(format, a1, a2, a3, a4)
  377. char *format;
  378. long a1, a2, a3, a4;
  379. {
  380.     unsetraw();
  381.     resetcursor();
  382.     fputc('\n', stderr);
  383.     fprintf(stderr, format, a1, a2, a3, a4);
  384.     sleep(5);
  385.     exit(1);
  386. }
  387.  
  388. static unsigned char ocursorstart, ocursorend;
  389. unsigned char cursorstart, cursorend;
  390. int cursorset;
  391.  
  392. /* Save the old value of the cursor then put in the new value.
  393.  */
  394. # define READCURSORPOS  0x03
  395. # define SETCURSORTYPE  0x01
  396. # define BIOSVIDEO  0x10
  397. setcursor()
  398. {
  399. #ifdef OS2LARN
  400.   USHORT  rc;
  401.   VIOCURSORINFO   curinfo;
  402.  
  403.   if (cursorset == 0)
  404.       return;
  405.  
  406.   /* Save the cursor type in 'ocursorstart' and 'ocursorend'. 
  407.   */
  408.   rc = VioGetCurType((PVIOCURSORINFO) &curinfo, (HVIO) NULL);
  409.   if (rc != 0)
  410.   {
  411.       /* errors don't happen. */
  412.   }
  413.   ocursorstart = curinfo.yStart;
  414.   ocursorend   = curinfo.cEnd;
  415.  
  416.   /* set the cursor type according to global variables
  417.      'cursorstart' and 'cursorend'.
  418.   */
  419.   curinfo.cEnd   = cursorend;
  420.   curinfo.yStart = cursorstart;
  421.   curinfo.cx     = 0; /* default width, 1 char */
  422.   curinfo.attr   = 0; /* 'Normal' attribute */
  423.  
  424.   rc = VioSetCurType((PVIOCURSORINFO) &curinfo, (HVIO) NULL);
  425.   if (rc != 0)
  426.   {
  427.       /* errors don't happen. */
  428.   }
  429.  
  430. #else
  431.     union   REGS    regs;
  432.  
  433.     if (cursorset == 0)
  434.         return;
  435.  
  436.     regs.h.ah = READCURSORPOS;
  437.     regs.h.bh = 0;
  438.     int86(BIOSVIDEO, ®s, ®s);
  439.     ocursorstart = regs.h.ch;
  440.     ocursorend = regs.h.cl;
  441.  
  442.     regs.h.ah = SETCURSORTYPE;
  443.     regs.h.bh = 0;
  444.     regs.h.ch = cursorstart;
  445. #if 0
  446.     regs.h.ch = 0x20 ;
  447. #endif
  448.     regs.h.cl = cursorend;
  449.     int86(BIOSVIDEO, ®s, ®s);
  450. #endif
  451. }
  452.  
  453. /* Restore the old cursor upon exit
  454.  */
  455. resetcursor()
  456. {
  457. #ifdef OS2LARN
  458.   VIOCURSORINFO   curinfo;
  459.  
  460.   if (cursorset == 0)
  461.       return;
  462.  
  463.   curinfo.cEnd   = ocursorend;
  464.   curinfo.yStart = ocursorstart;
  465.   curinfo.cx     = 0; /* default width, 1 char */
  466.   curinfo.attr   = 0; /* 'Normal' attribute */
  467.  
  468.   VioSetCurType((PVIOCURSORINFO) &curinfo, (HVIO) NULL);
  469. #else
  470.     union   REGS    regs;
  471.  
  472.     if (cursorset == 0)
  473.         return;
  474.     regs.h.ah = SETCURSORTYPE;
  475.     regs.h.bh = 0;
  476.     regs.h.ch = ocursorstart;
  477.     regs.h.cl = ocursorend;
  478.     int86(BIOSVIDEO, ®s, ®s);
  479. #endif
  480. }
  481. # endif /* MSDOS */
  482.